import pygame
import pyautogui
import json
import time
import math

def smooth_f(x,sensitivity):
    if abs(x)<0.7:
        return x
    else:
        return x*sensitivity

class JoystickMouse:
    def __init__(self, config_file="config.json"):
        pyautogui.FAILSAFE = False
        pyautogui.PAUSE = 1./240.
        self.load_config(config_file)
        self.init_joystick()
        self.button_states = {}
        self.hat_state = (0, 0)
        self.running = True
        self.t0 = time.time()
        self.accdx = 0.
        self.accdy = 0.

    def load_config(self, config_file):
        with open(config_file) as f:
            self.config = json.load(f)
        
        # 设置默认值
        self.mouse_config = self.config.get("mouse_move", {})
        self.scroll_config = self.config.get("mouse_scroll", {})
        self.buttons_config = self.config.get("mouse_buttons", [])
        
        # 鼠标移动死区和灵敏度
        self.deadzone = self.mouse_config.get("deadzone", 0.1)
        self.sensitivity = self.mouse_config.get("sensitivity", 500)

        # 滚动设置
        self.scroll_deadzone = self.scroll_config.get("deadzone", 0.15)
        self.scroll_sensitivity = self.scroll_config.get("sensitivity", 50)

    def init_joystick(self):
        pygame.init()
        pygame.joystick.init()
        
        if pygame.joystick.get_count() == 0:
            raise RuntimeError("未检测到摇杆设备！")
            
        self.joystick = pygame.joystick.Joystick(0)
        self.joystick.init()
        print(f"摇杆名称: {self.joystick.get_name()}")

    def handle_mouse_move(self):
        axis_x = self.joystick.get_axis(self.mouse_config["axis_x"])
        axis_y = self.joystick.get_axis(self.mouse_config["axis_y"])

        # 应用死区
        if abs(axis_x) < self.deadzone: axis_x = 0
        if abs(axis_y) < self.deadzone: axis_y = 0

        # 计算移动量并应用灵敏度
        self.accdx += smooth_f(axis_x,self.sensitivity)
        self.accdy += smooth_f(axis_y,self.sensitivity)

        if abs(self.accdx)>=1 or abs(self.accdy)>=1:
            pyautogui.moveRel(int(self.accdx), int(self.accdy))#, relative=True)
            if abs(self.accdx)>=1:
                self.accdx -= int(self.accdx)
            if abs(self.accdy)>=1:
                self.accdy -= int(self.accdy)

    def handle_mouse_scroll(self):
        axis = self.joystick.get_axis(self.scroll_config["axis_y"])
        if abs(axis) > self.scroll_deadzone:
            scroll_amount = -axis * self.scroll_sensitivity  # 调整滚动方向
            pyautogui.scroll(int(scroll_amount))

    def handle_buttons(self):
        for btn in self.buttons_config:
            button_id = btn["button"]
            action = btn["action"]
            current_state = self.joystick.get_button(button_id)
            previous_state = self.button_states.get(button_id, False)

            if current_state and not previous_state:
                if action[:6]=='mouse:':
                    pyautogui.mouseDown(button=action[6:])
                elif action[:4]=='key:':
                    i = action.find('+')
                    if i==-1:
                        pyautogui.keyDown(key=action[4:])
                    else:
                        key0 = action[4:i]
                        key1 = action[i+1:]
                        pyautogui.keyDown(key=key0)
                        pyautogui.keyDown(key=key1)
            elif not current_state and previous_state:
                if action[:6]=='mouse:':
                    pyautogui.mouseUp(button=action[6:])
                elif action[:4]=='key:':
                    i = action.find('+')
                    if i==-1:
                        pyautogui.keyUp(key=action[4:])
                    else:
                        key0 = action[4:i]
                        key1 = action[i+1:]
                        pyautogui.keyUp(key=key1)
                        pyautogui.keyUp(key=key0)
            
            self.button_states[button_id] = current_state

    def handle_hat(self):
        # 获取当前帽子开关状态
        current_hat = self.joystick.get_hat(0)  # 假设只有一个帽子开关

        # 定义方向对应的按键值
        directions = {
            (0, 1): 'up',       # 上
            (0, -1): 'down',    # 下
            (-1, 0): 'left',    # 左
            (1, 0): 'right',    # 右
        }

        # 如果上一个方向键被按下且当前未被按下，则释放该键
        if self.hat_state in directions:
            prev_key = directions[self.hat_state]
            if current_hat != self.hat_state:
                pyautogui.keyUp(prev_key)

        # 如果当前方向键被按下，则触发 keyDown
        if current_hat in directions:
            current_key = directions[current_hat]
            pyautogui.keyDown(current_key)
            time.sleep(0.1)

        # 更新帽子开关状态
        self.hat_state = current_hat

    def run(self):
        try:
            clock = pygame.time.Clock()
            while self.running:
                pygame.event.pump()  # 处理事件队列
                
                self.handle_mouse_move()
                self.handle_mouse_scroll()
                self.handle_buttons()
                self.handle_hat()
                #print(time.time() - self.t0)
                #self.t0 = time.time()
                # 检测退出组合键（L3 + R3）
                if self.joystick.get_button(8) and self.joystick.get_button(9):
                    self.running = False
                
                clock.tick(120)  # 限制120帧
                
        finally:
            pygame.quit()

if __name__ == "__main__":
    try:
        controller = JoystickMouse()
        controller.run()
    except Exception as e:
        print(f"错误: {str(e)}")